//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-06-14     ZhangYihua   first version
//
// Description  : transferring the latest vector status to different clock domain. The
//                min gap between two transmission is about (SYNC_NUM_D2S+1) clk_src
//                + (SYNC_NUM_S2D+2) clk_dst clock steps
//################################################################################

module sync_vect #(
parameter           VECT_BW                 = 9,
parameter           VECT_INI                = {VECT_BW{1'b0}},
parameter           SYNC_NUM_D2S            = 3,
parameter           SYNC_NUM_S2D            = 3
) ( 
input                                       rst_src_n,
input                                       clk_src,

input                                       src_pause,  // keep src_pause 1'b0 as far as possible for robustness
input               [VECT_BW-1:0]           src_vect,
output                                      src_busy,   // last vect is uncompleted

input                                       rst_dst_n,
input                                       clk_dst,

output              [VECT_BW-1:0]           dst_vect
);

//################################################################################
// define local varialbe and localparam
//################################################################################
wire                                        dst_tog_d2s;
wire                                        dst_unstable;
reg                 [VECT_BW-1:0]           dst_vect_d2s;
reg                                         dst_tog_d2s_1d;
wire                                        src_chg;
reg                                         src_tog;
reg                 [VECT_BW-1:0]           src_vect_hold;
wire                                        src_tog_s2d;
wire                                        dst_ce;
reg                                         dst_tog;
reg                 [VECT_BW-1:0]           dst_vect_hold;

//################################################################################
// main
//################################################################################

sync_dff #(
        .SYNC_NUM                       (SYNC_NUM_D2S                   ),
        .BW                             (1                              ),
        .INI                            (1'b0                           )
) u_tog_d2s ( 
        .rst_n                          (rst_src_n                      ),
        .clk                            (clk_src                        ),

        .d                              (dst_tog                        ),
        .q                              (dst_tog_d2s                    )
);

assign dst_unstable = (src_tog!=dst_tog_d2s) ? 1'b1 : 1'b0;
always@(posedge clk_src or negedge rst_src_n) begin
    if (rst_src_n==1'b0) begin
        dst_vect_d2s <=`U_DLY VECT_INI;
    end else begin
        if (dst_unstable==1'b0)
            dst_vect_d2s <=`U_DLY dst_vect_hold;
        else
            ;
    end
end

always@(posedge clk_src or negedge rst_src_n) begin
    if (rst_src_n==1'b0) begin
        dst_tog_d2s_1d <=`U_DLY 1'b0;
    end else begin
        dst_tog_d2s_1d <=`U_DLY dst_tog_d2s;
    end
end

assign src_chg  = |(src_vect ^ dst_vect_d2s);
assign src_busy = (src_tog!=dst_tog_d2s_1d) ? 1'b1 : 1'b0;
always@(posedge clk_src or negedge rst_src_n) begin
    if (rst_src_n==1'b0) begin
        src_tog       <=`U_DLY 1'b0;
        src_vect_hold <=`U_DLY VECT_INI;
    end else begin
        if ((src_chg==1'b1) && (src_pause==1'b0) && (src_busy==1'b0)) begin
            src_tog       <=`U_DLY ~src_tog;
            src_vect_hold <=`U_DLY src_vect;
        end else
            ;
    end
end

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

sync_dff #(
        .SYNC_NUM                       (SYNC_NUM_S2D                   ),
        .BW                             (1                              ),
        .INI                            (1'b0                           )
) u_tog_s2d ( 
        .rst_n                          (rst_dst_n                      ),
        .clk                            (clk_dst                        ),

        .d                              (src_tog                        ),
        .q                              (src_tog_s2d                    )
);

assign dst_ce = dst_tog ^ src_tog_s2d;
always@(posedge clk_dst or negedge rst_dst_n) begin
    if (rst_dst_n==1'b0) begin
        dst_tog       <=`U_DLY 1'b0;
        dst_vect_hold <=`U_DLY VECT_INI;
    end else begin
        if (dst_ce==1'b1) begin
            dst_tog       <=`U_DLY ~dst_tog;
            dst_vect_hold <=`U_DLY src_vect_hold;
        end else
            ;
    end
end
assign dst_vect = dst_vect_hold;

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off


// synopsys translate_on
`endif

endmodule
